package aiP.A3.MPS;

import aiP.A3.AuftragKomponente.AccessLayer.AuftragKomponenteFacade;
import aiP.A3.AuftragKomponente.AccessLayer.IAuftragServices;
import aiP.A3.AuftragKomponente.DataAccessLayer.Entity.Angebot;
import aiP.A3.AuftragKomponente.DataAccessLayer.Entity.Auftrag;
import aiP.A3.BuchhaltungKomponente.AccessLayer.BuchhaltungKomponenteFacade;
import aiP.A3.BuchhaltungKomponente.AccessLayer.IBuchhaltungServices;
import aiP.A3.BuchhaltungKomponente.DataAccessLayer.Entity.Kunde;
import aiP.A3.BuchhaltungKomponente.DataAccessLayer.Entity.Rechnung;
import aiP.A3.Client.Monitor.Monitor;
import aiP.A3.FOLKSBankAdapter.AccessLayer.BankAdapterFacade;
import aiP.A3.FertigungKomponente.DataAccessLayer.Entity.Bauteil;
import aiP.A3.MPS.Interfaces.IServerInstance;
import aiP.A3.PersistenceService.Persist;
import aiP.A3.PersistenceService.iEntity;
import aiP.A3.UPPSAdapter.ITransport_Adapter;
import aiP.A3.UPPSAdapter.TransportAdapter;
import aiP.A3.VersandKomponente.AccessLayer.IVersandServicesFuerTransportadapter;
import aiP.A3.VersandKomponente.AccessLayer.VersandKomponenteFacade;
import aiP.A3.VersandKomponente.DataAccessLayer.DTO.TransportauftragDTO;
import aiP.A3.VersandKomponente.DataAccessLayer.Entity.Transportauftrag;

import java.io.IOException;
import java.math.BigInteger;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.rmi.server.UnicastRemoteObject;
import java.security.SecureRandom;
import java.util.*;

/**
 * Created with IntelliJ IDEA.
 * User: Hero
 * Date: 15.05.14
 * Time: 15:18
 * To change this template use File | Settings | File Templates.
 */
public class ServerInstance implements IServerInstance {

    private static SecureRandom random = new SecureRandom();
    private boolean live = false;

    boolean running = false;

    final String serverId;
    final String monitorHost;
    final int monitorPort;

    private Thread ekg = null;
    private IAuftragServices iAS = null;
    private IBuchhaltungServices iBS = null;
    private IVersandServicesFuerTransportadapter iVST = null;
    private BankAdapterFacade baF = null;

    public ServerInstance(String monitorHost, int monitorPort) throws RemoteException {
        live = true;
        iAS = new AuftragKomponenteFacade();
        iBS = new BuchhaltungKomponenteFacade();
        iVST = new VersandKomponenteFacade();
        baF = new BankAdapterFacade();

        this.serverId = generateId();
        this.monitorHost = monitorHost;
        this.monitorPort = monitorPort;

        try {
            Registry registry = LocateRegistry.getRegistry(1173);
            System.out.println("___ServerInstance___ : " + this.getId());
            IServerInstance toBind = this;
            registry.rebind(this.getId().toUpperCase(), UnicastRemoteObject.exportObject(toBind, 0));

            //this.startEKG();
        } catch (RemoteException e1){
            e1.printStackTrace();
        }


    }

    private String generateId() {
        return new BigInteger(130, ServerInstance.random).toString(32).substring(0, 6);
    }

    public String getId() {
        return this.serverId;
    }

    @Override
    public void CreateAngebot(Set<Angebot> angebot) throws RemoteException {
        iAS.CreateAngebot(angebot);
    }

    @Override
    public void CreateAuftrag(Auftrag auftrag) throws RemoteException {
        iAS.CreateAuftrag(auftrag);
    }

    @Override
    public void CreateRechnung(Rechnung rechnung) throws RemoteException {
        iBS.CreateRechnung(rechnung);
    }

    @Override
    public void CreateTransportauftrag(Transportauftrag transportauftrag) throws RemoteException {
        iVST.CreateTransportauftrag(transportauftrag);
    }


    @Override
    public Collection<iEntity> getAllBauteile() throws RemoteException, NotBoundException{
        return Persist.getInstance().load(iEntity.BAUTEIL);
    }

    @Override
    public Collection<iEntity> getAllCustomer() throws RemoteException, NotBoundException{
        return Persist.getInstance().load(iEntity.KUNDE);
    }

    @Override
    public Collection<iEntity> getAllAuftraege() throws RemoteException, NotBoundException{
        return Persist.getInstance().load(iEntity.AUFTRAG);
    }

    @Override
    public Collection<iEntity> getAllAngebote() throws RemoteException, NotBoundException{
        return Persist.getInstance().load(iEntity.ANGEBOT);
    }

    @Override
    public Collection<iEntity> getAllZahlungseingaenge() throws RemoteException, NotBoundException {
        return Persist.getInstance().load(iEntity.ZAHLUNGSEINGANG);
    }

    @Override
    public void getZahlungseingaengeFromQueue() throws IOException, InterruptedException {
        baF.EmpfangeZahlungseingaenge();
    }

    @Override
    public Collection<iEntity> getAllRechnungen() throws RemoteException, NotBoundException {
        return Persist.getInstance().load(iEntity.RECHNUNG);
    }

    @Override
    public Collection<iEntity> getAllTransportauftraege() throws RemoteException, NotBoundException {
        return Persist.getInstance().load(iEntity.TRANSPORTAUFTRAG);
    }


    public void startEKG() throws RemoteException {
        this.ekg = new ServerEKG(this);
        this.running = true;
        this.ekg.start();
    }

    public void stopEKG() throws RemoteException {
        this.running = false;
    }

    @Override
    public void setAlive(boolean alive) throws RemoteException, NotBoundException {
        live = alive;
    }

    @Override
    public boolean isAlive() throws RemoteException, NotBoundException {
        return live;  //To change body of implemented methods use File | Settings | File Templates.
    }

    @Override
    public void createTransportauftrag(Transportauftrag auftrag) throws RemoteException, NotBoundException{
        Persist.getInstance().save(auftrag);
    }

    @Override
    public boolean sendToVersand(Transportauftrag transportauftrag) throws IOException, NotBoundException {
        ITransport_Adapter transport_adapter = new TransportAdapter(this);
        return transport_adapter.postToUpps(transport_adapter.createTransportAuftrag(transportauftrag));
    }

    public static void main(String[] args) throws RemoteException {
        ServerInstance sInstance = new ServerInstance("localhost", Monitor.SERVER_PORT);
        System.out.println("________ENDE_________");
        sInstance.startEKG();
    }

    public String toString(){
        return "___Serverinstance : " + getId();
    }


    //////////////////////
    // Entkopplung vom Dispatcher
    ////

    public Collection<Angebot> getAngebotCol(int AngebotID) throws RemoteException, NotBoundException {
        Collection<Angebot> result = new HashSet<Angebot>();
        for(iEntity elem: getAllAngebote()){
            if(elem instanceof Angebot){
                Angebot tAngebot = (Angebot)elem;
                if(AngebotID == tAngebot.getAngebotsnr())
                    result.add(tAngebot);
            }
        }
        return result;
    }

    public Map<Integer, Auftrag> getAuftragsMapCol() throws RemoteException, NotBoundException {
        Collection<iEntity> col = getAllAuftraege();
        Map<Integer, Auftrag> result = new HashMap<Integer, Auftrag>();
        for(iEntity elem : col){
            if (elem instanceof Auftrag){
                Auftrag tAuftrag = (Auftrag)elem;
                if (tAuftrag.getIstAbgeschlossen() == 0)
                    result.put(tAuftrag.getAuftragsnr(), tAuftrag);
            }
        }
        return result;
    }


    public Map<Integer, Bauteil> getBautei_Id() throws NotBoundException, RemoteException {
        Collection<iEntity> col = getAllBauteile();
        Map<Integer, Bauteil> result = new HashMap<Integer, Bauteil>();
        for (iEntity elem : col) {
            if (elem instanceof Bauteil) {
                Bauteil tBauteil = (Bauteil) elem;
                result.put(tBauteil.getBauteilId(), tBauteil);
            }
        }
        return result;  //To change body of implemented methods use File | Settings | File Templates.
    }

    public Map<Integer, Kunde> getKundenMapByID() throws NotBoundException, RemoteException {
        Collection<iEntity> col = getAllCustomer();//Persist.getInstance().load(iEntity.KUNDE);

        Map<Integer, Kunde> result = new HashMap<Integer, Kunde>();
        for (iEntity elem : col) {
            if (elem instanceof Kunde) {
                Kunde tKunde = (Kunde) elem;
                result.put(tKunde.getKundeId(), tKunde);
            }
        }
        return result; //To change body of implemented methods use File | Settings | File Templates.
    }

}
